/*
Object Slicer by Jefferson D. Lim
email: jeffdavidlim@yahoo.com

Some Features:

Subfragmentation parameters 
- This will slice the initially sliced objects.
- I've only limited the slicing up to 3 subfragmentions.
- An option to choose between slice mode or boolean mode.

Slice mode: 
- Uses the slice modifier for slicing the object.
- Internally, the script applies slice & capholes modifier that has random rotations.
- Its much safer to use this method rather than the boolean one. 

Boolean mode: 
- As we all know, booleans in max can be very unstable.. so use with caution. 
- This basically creates a plane.. applies a noise, shell and a subdivide modifier on top.
- You can control the values of the shell "thickness", plane "Segments", "Subdivision" size, and 
noise "fractal" strength within the UI. 
- Thus the created plane is used to slice through the selected object. 

An info text area to show the summary of slicing.
- shows percentage of open obejcts
- Includes the number of sliced objects. 
- Time elapsed.

- The Slice Rotation parameter lets you control the random rotation limit for the slice planes/plane 
objects.
- also supports changing the rotation controller for each fragment

- An option/button to randomize wire colors for each object after slicing 
- A show progress button 

- Note that using the show progress button can sometimes hang the UI, it means the it wont be 
updating the progress bar since a lot of objects are being processed in the background. (i think) but 
slicing is still in motion. 

- Also note that at subfragment 0, using the progress bar wont show you any progress. 

- The fragments are automatically selected after slicing 
- Works only on poly objects 
- Mapping is retained after slicing (thanks to the slice mod)
- option to assign a material ID for the insides of the the fractures object.
*/

rollout tera_slicer "ObjSlicer 0.7" width:155 height:385
(
local Fragmentation, Frag_Recursive, SlicePlanes, DetachPolyElements_fn, PolyObjFilter, RanColor, ApplyRotCont, UpdateSubFrac, UpdateFrac, CheckOpenEdges
---
local sel_obj = undefined
local fragment_name = "Fragment_"
local DetachedObj = undefined
---
local bounds = false
local bounder = undefined
---
local thickval
local segval
local subdval
local fracval
local capholesval
local xformval
---
local slicer_rot_min_x, slicer_rot_min_y, slicer_rot_min_z
local slicer_rot_max_x, slicer_rot_max_y, slicer_rot_max_z
---
local status_info = false
local prog_enable = false
---
local iternum = 5
local subfragnum = 0
local subiternum = 3
local rot_min = 0
local rot_max = 360
local the_counter = 0
---
local the_orig, the_clone
local rotcont, matidval, tera_slicelock
local use_slice, use_shell, use_rotcont, use_rancolor, use_matid, use_reactor, use_simcloth

fn PolyObjFilter obj = (classof obj == Editable_Poly)
fn RanColor = if selection != undefined do (for i in selection do i.wirecolor = random black white)
fn ApplyRotCont Obj =
	(
	if use_rotcont do
		(
		case rotcont of
			(
			1: ( Obj.rotation.controller = Euler_XYZ() )
			2: ( Obj.rotation.controller = linear_rotation() )
			3: ( Obj.rotation.controller = tcb_rotation() )
			)
		)
	)
	
	subRollout tera_slicer_subroll "" pos:[5,155] width:145 height:175
	pickbutton frac_obj "- NONE -" pos:[10,10] width:114 height:21 filter:PolyObjFilter toolTip:"Select a Valid Poly Object"
	checkbutton lock_bot "" pos:[124,10] width:21 heigth:21 enabled:false images:#(getdir #maxroot + "\UI\Icons\SnapsControls_16i.bmp",undefined,32,1,3,2,4)
	edittext the_prefix "" pos:[37,34] width:108 height:17 text:fragment_name
	spinner iter "" pos:[85,56] width:60 height:16 range:[1,9999,5] type:#integer
	radiobuttons method_rd "" pos:[5,85] width:132 height:16 labels:#("Slice", "Boolean") default:1 columns:2
	spinner subfrag "" pos:[85,110] width:60 height:16 range:[0,3,0] type:#integer
	spinner subiter "" pos:[85,130] width:60 height:16 range:[0,9999,3] type:#integer
	button frac_bot "FRACTURE" pos:[5,335] width:145 height:30 enabled:false
	checkbutton status_chk "" pos:[5,370] width:145 height:10 toolTip:"Show Status Info"	
	progressBar slice_pb "" pos:[155,6] width:10 height:374 orient:#vertical
	GroupBox grp_subfrags "" pos:[5,100] width:145 height:50
	GroupBox grp_main "" pos:[5,0] width:145 height:80
	GroupBox grp_status " Status Info: " pos:[5,385] width:145 height:65
	label iter_lbl "Iterations:" pos:[35,57] width:50 height:15
	label subfrag_lbl "Sub-Fragments:" pos:[10,110] width:75 height:15
	label subiter_lbl "Sub-Iterations:" pos:[15,130] width:69 height:15
	label prefix_lbl "Prefix:" pos:[10,35] width:28 height:15
	label tera_level "" pos:[10,400] width:135 height:15
	label tera_objs "" pos:[10,415] width:135 height:15
	label tera_prog "" pos:[10,430] width:135 height:15
		

-- the main recursive function
fn Fragmentation the_num =
	(

	case the_num of
		(
		0: 	(
			for i in 1 to iternum do (the_counter += 1; /*format  "slicing %...\n" the_counter;*/ SlicePlanes sel_obj bounds)		
			DetachPolyElements_fn sel_obj
			gc()
			)
		1:	(
			Fragmentation 0	
			Frag_Recursive "1"
			)
		2:	(
			Fragmentation 1	
			Frag_Recursive "2"
			)
		3:	(
			Fragmentation 2	
			Frag_Recursive "3"
			)
		)
	)

-- the sub-recursive function
fn Frag_Recursive frag_num =
	(
	frag_array = execute ("$" + fragment_name + "* as array")	
	subiternum = subiter.value

	if prog_enable then
		(		
		frag_count = frag_array.count
		for i in 1 to frag_count do
			(
			sel_obj = frag_array[i]
			iternum = subiternum
			Fragmentation 0
			----
			the_percent = 100.0*i/frag_array.count
			slice_pb.value = the_percent
			tera_level.caption = ("Subfragment Level "+  frag_num)
			tera_objs.caption = ((frag_array.count-i) as string + " Objects Left")
			tera_prog.caption = (the_percent as string + "%")			
			)
		slice_pb.value = 0
		)
	else
		(
		sel_obj = frag_array
		iternum = subiternum
		Fragmentation 0
		)
	gc()
	)

-- function for slicing
-- ran values should be boolean
-- it will decide wheter to use the object or a dummy
-- as bounding slice positions
mapped fn SlicePlanes obj ran =
	(
	if obj != undefined do
		(
		local ran1
		local ran2		
		local objholder
		
		if not ran then -- using the picked object
			(
			ran1 = obj.min
			ran2 = obj.max			
			objholder = obj
			)
		else 			-- using the bounding box
			(
			ran1 = bounder.min
			ran2 = bounder.max			
			objholder = bounder
			)
		
		ran_pos = (random ran1 ran2)
		ran_rot_x = (random slicer_rot_min_x slicer_rot_max_x)
		ran_rot_y = (random slicer_rot_min_y slicer_rot_max_y)
		ran_rot_z = (random slicer_rot_min_z slicer_rot_max_z)
		ran_rot = eulerangles ran_rot_x ran_rot_y ran_rot_z
	
		tera_cap_holes = (Cap_Holes name:"tera_cap_holes")
		
		if not use_slice then
			(			
			tera_slice = (SliceModifier name:"tera_slice")			
			addmodifier obj tera_slice		
			obj.modifiers["tera_slice"].Slice_Type = 1				
			obj.modifiers["tera_slice"].slice_plane.pos = ran_pos-objholder.pos		
			obj.modifiers["tera_slice"].slice_plane.rotation = ran_rot
			addmodifier obj tera_cap_holes		
			convertTo obj Editable_Poly
			)
		else
			(
			the_length = length (ran2 - ran1)
			tera_noise = (Noisemodifier name:"tera_noise")			
 			tera_shell = (Shell name:"tera_shell" outeramount:thickval)
			tera_subdiv = (Subdivide name:"tera_subdiv" size:subdval)			
			--  
			the_plane = in coordsys objholder plane length:(the_length*3) width:(the_length*3) pos:((ran_pos/1.25)*(objholder.pos)) rotation:ran_rot
			the_plane.lengthsegs = the_plane.widthsegs = segval	
			
			addmodifier the_plane tera_noise			
			the_plane.modifiers["tera_noise"].seed = random 1 100
			the_plane.modifiers["tera_noise"].fractal = on
			the_plane.modifiers["tera_noise"].strength = [fracval,fracval,fracval]
			
			addmodifier the_plane tera_shell			
			addmodifier the_plane tera_subdiv			
			
			convertTo obj Editable_Mesh
			convertTo the_plane Editable_Mesh
			
			if use_shell do meshop.breakverts obj #{1}
			obj - the_plane
			delete the_plane
			
			if use_matid do
				(
				the_faces = getfaceselection obj
				for i in the_faces do setFaceMatID obj i matidval
				)
				
			if capholesval and not use_shell do
				(
				addmodifier obj tera_cap_holes
				convertTo obj Editable_Mesh			
				)
			)
		)
	)
	
------------------------------------- from Hacksawtools:Chris Harvey 
-- detaches poly elements
mapped fn DetachPolyElements_fn SourceOBJ =
	(
	MasterObj = SourceOBJ
	convertTo MasterObj Editable_Poly
	faceCount = MasterObj.getnumfaces()	
	FaceTest = ((faceCount) != 0)
	
	
	for i in 1 to faceCount while FaceTest do	
		(
		newName = (uniquename fragment_name)		
		MasterObj.EditablePoly.SetSelection #Face #{1}
		MasterObj.selectElement()
		TargetElement = polyop.getFaceSelection MasterObj
		polyop.detachFaces MasterObj TargetElement asNode:true name:newName		
		
		NewObj = getnodebyname newName	
		convertTo NewObj (Editable_Poly)
		if use_shell do
			(
			the_num = for i in 1 to getnumverts NewObj collect i
			NewObj.weldThreshold = 0.2
			polyop.weldVertsByThreshold NewObj (the_num as bitarray)
			)
		ResetTransform NewObj
		ResetScale NewObj
		ResetPivot NewObj
		centerpivot NewObj
		if xformval do resetXForm NewObj 			
		FaceTest = ((MasterObj.getnumfaces()) != 0)
		ApplyRotCont NewObj		
		)	
	delete MasterObj	
	)
	
fn slicemethod state =
	(
	local the_method
	the_roll = tera_slicer.tera_slicer_subroll.tera_slicer_boolean_mode
	case state of (1: (the_method = false); 2: (the_method = true))
	use_slice =
	the_roll.thickness_spn.enabled = 
	the_roll.segments_spn.enabled = 
	the_roll.subdivs_spn.enabled = 
	the_roll.fractal_spn.enabled = 
	the_roll.thick_lbl.enabled = 
	the_roll.segs_lbl.enabled = 
	the_roll.subd_lbl.enabled = 	
	the_roll.frac_lbl.enabled =	
	the_roll.matid_chk.enabled =
	the_roll.booltype_rd.enabled = the_method
	if the_roll.matid_chk.checked do
		(		
		the_roll.matid_lbl.enabled = 
		the_roll.matid_spn.enabled = true
		)
	if (not the_roll.matid_chk.enabled) do
		(
		the_roll.matid_lbl.enabled = 
		the_roll.matid_spn.enabled = false
		)
	case the_roll.booltype_rd.state of
		(
		1: the_roll.cap_holes_chk.enabled = the_method
		2: the_roll.cap_holes_chk.enabled = false
		)
	)
	
fn UpdateFrac =
	(	
	tera_slicer.tera_level.caption = ""
	tera_slicer.frac_obj.caption = "- NONE -"
	the_roll = tera_slicer.tera_slicer_subroll.tera_slicer_extraparameters
	the_roll.boundbox.enabled = false
	tera_slicer.frac_bot.enabled = false
	tera_slicer.lock_bot.enabled = false
	tera_slicer.lock_bot.checked = false
	tera_slicer.tera_Slicelock = false
	)

fn CheckOpenEdges Obj_Array =
	(
	if Obj_Array != undefined do
		(
		local the_stat = 0
		the_count = Obj_Array.count
		for i in 1 to the_count do
			(			
			the_openedge = polyop.getOpenEdges Obj_Array[i]			
			--format "i:% count:% bool:% stat:% val:%\n" i the_count the_openedge.isempty the_stat the_openedge
			if not the_openedge.isempty do the_stat += 1
			
			)
		the_prog = (100.0*the_stat/the_count) as integer
		return the_prog
		)
	)

---------------------------------------		
	
	
	on tera_slicer open do
		(
			thickval = 0.1
			segval = 30
			subdval = 6.0
			fracval = 25.0
			capholesval = false
			xformval = true
			slicer_rot_min_x = 0
			slicer_rot_min_y = 0
			slicer_rot_min_z = 0
			slicer_rot_max_x = 360
			slicer_rot_max_y = 360
			slicer_rot_max_z = 360
			tera_Slicelock = true
			use_slice = false
			use_shell = false
			use_rancolor = true
			use_rotcont = false
			use_matid = false
			use_reactor = false
			use_simcloth = false
			matidval = 5
			rotcont = 1
		)
		
	on tera_slicer close do
		(
		if bounder != undefined do 
			(		
			delete bounder
			bounder = undefined				
			)
		try(unhide the_orig; UPdateFrac())catch()
		)
		
	on frac_obj picked obj do
		(
		tera_slicer.lock_bot.checked = true
		tera_slicer.tera_slicelock = true
		tera_slicer.tera_slicer_subroll.tera_slicer_extraparameters.UpdateSubFrac obj
		)
	
	on lock_bot changed state do
		(
		tera_slicelock = state
		if not state then try(unhide the_orig; UPdateFrac() )catch()
		)
		
	on the_prefix changed text do (fragment_name = text)
	on iter changed val do (iternum = val)
	on method_rd changed state do (slicemethod state)
	on subfrag changed val do (subfragnum = val)
	on subiter changed val do (subiternum = val)
	
	on frac_bot pressed do
		(		
			undo off ()
			disableSceneRedraw()			
			if tera_Slicelock then
				(
				----
				max create mode	
				----
				the_orig = sel_obj
				hide the_orig
				try( execute ("delete $" + fragment_name + "*") )catch()
				the_clone = copy sel_obj --make a copy of the object to be fragmented			
				sel_obj = the_clone		 --set to another variable, this is the one to be sliced			
				time_start = timestamp() --
				Fragmentation subfragnum --do the fragmentation
				time_end = timestamp()   --
				----
				deselect $*
				all_frags = execute ("$" + fragment_name + "* as array")
				--selects the fragments
				select all_frags		
				--then tries to apply random wire colors to each
				if use_RanColor then RanColor()				
				--updates the info captions and resets the slicer
				tera_level.caption = ( (CheckOpenEdges Selection) as string + "% Open Objects")
				tera_objs.caption = (all_frags.count as string + " Fragments Created")
				tera_prog.caption = ("Time: " + ((time_end - time_start) / 1000.0) as string + " seconds")
				sel_obj = the_orig
				the_counter = 0			
				)
			else
				(				
				----
				max create mode	
				----
				the_clone = copy sel_obj --make a copy of the object to be fragmented			
				sel_obj = the_clone		 --set to another variable, this is the one to be sliced			
				time_start = timestamp() --
				Fragmentation subfragnum --do the fragmentation
				time_end = timestamp()   --
				----
				deselect $*
				all_frags = execute ("$" + fragment_name + "* as array")
				--selects the fragments
				select all_frags		
				--then tries to apply random wire colors to each
				if use_RanColor then RanColor()				
				--updates the info captions and resets the slicer				
				tera_level.caption = ( (CheckOpenEdges Selection) as string + "% Open Objects")
				tera_objs.caption = (all_frags.count as string + " Fragments Created")
				tera_prog.caption = ("Time: " + ((time_end - time_start) / 1000.0) as string + " seconds")
				sel_obj = undefined
				the_counter = 0
				UpdateFrac()			
				)
			the_roll = tera_slicer.tera_slicer_subroll.tera_slicer_extraparameters			
			if use_reactor do the_roll.setObjMass 1
			if use_simcloth do the_roll.setObjMass 2
			enableSceneRedraw()
		)
	on status_chk changed state do
		(
		if state then
			(
			tera_slicer.height = 455
			)
		else
			(
			tera_slicer.height = 385		
			)
		)
)

rollout tera_slicer_rotation_ops "Rotation Parameters" width:135 height:160 rolledup:true
(
	local UpdateTeraSlicerRot, LockedMode
	local defmin = 0
	local defmax = 360
	local lockstate = false
	local rotcont, use_rotcont

	spinner rot_min_x_spn "" pos:[20,20] width:45 height:16 range:[-360,360,0] type:#integer	
	spinner rot_max_x_spn "" pos:[82,20] width:45 height:16 range:[-360,360,360] type:#integer
	spinner rot_min_y_spn "" pos:[20,40] width:45 height:16 range:[-360,360,0] type:#integer
	spinner rot_max_y_spn "" pos:[82,40] width:45 height:16 range:[-360,360,360] type:#integer
	spinner rot_min_z_spn "" pos:[20,60] width:45 height:16 range:[-360,360,0] type:#integer
	spinner rot_max_z_spn "" pos:[82,60] width:45 height:16 range:[-360,360,360] type:#integer
	button forward_bot_1 ">" pos:[66,21] width:16 height:15 toolTip:"Copy to min value to max value"
	button forward_bot_2 ">" pos:[66,41] width:16 height:15 toolTip:"Copy to min value to max value"
	button forward_bot_3 ">" pos:[66,61] width:16 height:15 toolTip:"Copy to min value to max value"
	button reset_bot "Reset" pos:[82,80] width:45 height:15	
	checkbutton lock_bot "Lock" pos:[5,80] width:45 height:15
	button separator_1 "" pos:[2,100] width:127 height:2 enabled:false
	checkbox rotcont_chk "" pos:[2,108] width:20 height:15
	dropdownList rotcont_drp "" pos:[22,105] width:108 height:21 enabled:false items:#("Euler XYZ", "Linear Rotation", "TCB Rotation") selection:1
	button rotcont_bot "Apply Rotation Controller" pos:[2,130] width:126 height:20 toolTip:"Applies the Controller to Selection" enabled:false
	label x_lbl "X :" pos:[5,22] width:15 height:15
	label y_lbl "Y :" pos:[5,42] width:15 height:15	
	label z_lbl "Z :" pos:[5,62] width:15 height:15
	label min_lbl "Min" pos:[30,5] width:25 height:15
	label max_lbl "Max" pos:[90,5] width:25 height:15
	
	
	fn UpdateTeraSlicerRot =
		(
		tera_slicer.slicer_rot_min_x = rot_min_x_spn.value
		tera_slicer.slicer_rot_min_y = rot_min_y_spn.value
		tera_slicer.slicer_rot_min_z = rot_min_z_spn.value
		tera_slicer.slicer_rot_max_x = rot_max_x_spn.value
		tera_slicer.slicer_rot_max_y = rot_max_y_spn.value
		tera_slicer.slicer_rot_max_z = rot_max_z_spn.value
		)
		
	fn LockedMode the_val the_set =		
		(
		the_roll = tera_slicer_rotation_ops	
		case the_set of
			(
			0: the_roll.rot_min_x_spn.value = the_roll.rot_min_y_spn.value = the_roll.rot_min_z_spn.value = the_val
			1: the_roll.rot_max_x_spn.value = the_roll.rot_max_y_spn.value = the_roll.rot_max_z_spn.value = the_val
			)		
		UpdateTeraSlicerRot()
		)	

	on rot_min_x_spn changed val do
		( if not lockstate then UpdateTeraSlicerRot() else LockedMode val 0)
	on rot_max_x_spn changed val do
		( if not lockstate then UpdateTeraSlicerRot() else LockedMode val 1)
	on rot_min_y_spn changed val do
		( if not lockstate then UpdateTeraSlicerRot() else LockedMode val 0)
	on rot_max_y_spn changed val do
		( if not lockstate then UpdateTeraSlicerRot() else LockedMode val 1)
	on rot_min_z_spn changed val do
		( if not lockstate then UpdateTeraSlicerRot() else LockedMode val 0)
	on rot_max_z_spn changed val do
		( if not lockstate then UpdateTeraSlicerRot() else LockedMode val 1)
	on forward_bot_1 pressed do
		(rot_max_x_spn.value = rot_min_x_spn.value; UpdateTeraSlicerRot() )
	on forward_bot_2 pressed do
		(rot_max_y_spn.value = rot_min_y_spn.value; UpdateTeraSlicerRot() )
	on forward_bot_3 pressed do
		(rot_max_z_spn.value = rot_min_z_spn.value; UpdateTeraSlicerRot() )
	on reset_bot pressed do
	(
	rot_min_x_spn.value = rot_min_y_spn.value = rot_min_z_spn.value = defmin
	rot_max_x_spn.value = rot_max_y_spn.value = rot_max_z_spn.value = defmax
	UpdateTeraSlicerRot()
	)
	on lock_bot changed state do
		(lockstate = state)
	on rotcont_bot pressed do
	(
	for i in selection do
		(
		try(tera_slicer.ApplyRotCont i)catch()
		)
	)
	on rotcont_chk changed state do
		(tera_slicer.use_rotcont = state; rotcont_drp.enabled = state; rotcont_bot.enabled = state)
	on rotcont_drp selected item do
		(tera_slicer.rotcont = item)
)

rollout tera_slicer_boolean_mode "Boolean Options" width:135 height:200
(
	local thickval = 0.1
	local segval = 30
	local subdval = 6.0
	local fracval = 25.0
	local capholesval = false
	local xformval = true

	spinner thickness_spn "" pos:[75,10] width:50 height:16 enabled:false range:[0,9999,0.1] type:#float scale:0.01
	spinner segments_spn "" pos:[75,30] width:50 height:16 enabled:false range:[1,9999,30] type:#integer
	spinner subdivs_spn "" pos:[75,50] width:50 height:16 enabled:false range:[0.001,9999.9,6] type:#float scale:0.01
	spinner fractal_spn "" pos:[75,70] width:50 height:16 enabled:false range:[-9999,9999,25] type:#float scale:0.01
	spinner matid_spn "" pos:[80,140] width:45 height:16 enabled:false range:[0,99,5] type:#integer scale:1
	checkbox cap_holes_chk "Cap Holes" pos:[5,100] width:125 height:15 enabled:false checked:false	
	checkbox pbool_chk "Use Power Booleans" pos:[5,115] width:125 height:15 enabled:false
	checkbox matid_chk "Checkbox" pos:[5,140] width:15 height:15 enabled:false
	radiobuttons booltype_rd "" pos:[5,170] width:112 height:16 enabled:false labels:#("Solid", "Shell") default:1 columns:2
	label thick_lbl "Thickness:" pos:[20,10] width:55 height:15 enabled:false
	label segs_lbl "Segments:" pos:[23,30] width:50 height:15 enabled:false
	label subd_lbl "Subdivisions:" pos:[10,50] width:65 height:15 enabled:false
	label frac_lbl "Fractal:" pos:[36,70] width:35 height:15 enabled:false
	label matid_lbl "Material ID:" pos:[23,141] width:55 height:15 enabled:false
	button separator_1 "" pos:[2,92] width:127 height:2 enabled:false
	button separator_2 "" pos:[2,132] width:127 height:2 enabled:false
	button separator_3 "" pos:[2,162] width:127 height:2 enabled:false
	
	
	on thickness_spn changed val do
		(tera_slicer.thickval = val)
	on segments_spn changed val do
		(tera_slicer.segval = val)
	on subdivs_spn changed val do
		(tera_slicer.subdval = val)
	on fractal_spn changed val do
		(tera_slicer.fracval = val)
	on matid_spn changed val do
		(tera_slicer.matidval = val)
	on cap_holes_chk changed state do
		(tera_slicer.capholesval = state)
	on matid_chk changed state do
		(tera_slicer.use_matid = matid_lbl.enabled = matid_spn.enabled = state)
	on booltype_rd changed state do
		(
		case state of 
			(
			1: (tera_slicer.use_shell = false; cap_holes_chk.enabled = true)
			2: (tera_slicer.use_shell = true; cap_holes_chk.enabled = false)
			)
		)

)
rollout tera_slicer_extraparameters "Extra Parameters" width:135 height:190
(
	local bounder = undefined
	local the_selobj	
	
	checkbutton boundbox "Bounding Box" pos:[5,5] width:101 height:20 enabled:false toolTip:"Use Dummy Box as Center" checked:false	
	checkbutton prog_chk "" pos:[106,5] width:19 height:20 toolTip:"Show Progress Info" images:#("C:\3dsmax6\\UI\Icons\Radiosity_16i.bmp", undefined, 6, 6, 5, 6, 5)
	checkbox rancolor_chk "" pos:[5,37] width:15 height:15 checked:true
	button rancolor_bot "Random Wire Colors" pos:[20,35] width:105 height:20
	button detach_all "Detach Elements" pos:[5,65] width:120 height:20 toolTip:"Detach Poly Elements for Selected Objects"
	checkbox xform_chk "" pos:[5,87] width:15 height:15 checked:true
	button xformoff_bot "Xform SubObject" pos:[20,85] width:105 height:20 toolTip:"Check to auto-apply Xform Mod. Press to set Xfrom subobject OFF on selected object(s)"	
	checkbox reactor_chk "" pos:[5,137] width:15 height:15 checked:false
	button reactormass_bot "Apply Reactor Mass" pos:[20,135] width:105 height:20 toolTip:"Automatically apply Reactor mass to selected object(s)"
	checkbox simcloth_chk "" pos:[5,157] width:15 height:15 checked:false
	button simclothmass_bot "Apply Simcloth Mass" pos:[20,155] width:105 height:20 toolTip:"Automatically apply Reactor mass to selected object(s)"
	spinner reactormult_spn "" pos:[55,115] width:70 height:16 range:[1,999999,1000] type:#float scale:0.1
	button separator_1 "" pos:[2,30] width:127 height:2 enabled:false	
	button separator_2 "" pos:[2,60] width:127 height:2 enabled:false
	button separator_3 "" pos:[2,110] width:127 height:2 enabled:false
	label reactormult_lbl "Multipliter :" pos:[3,115] width:50 height:15	
	

fn UpdateSubFrac obj =
	(	
	if obj != undefined do
		(		
		the_selobj = obj
		tera_slicer.sel_obj = obj
		tera_slicer.frac_obj.caption = obj.name
		tera_slicer.lock_bot.enabled = true		
		boundbox.enabled = true
		tera_slicer.frac_bot.enabled = true
		tera_slicer.iternum = tera_slicer.iter.value
		when the_selobj deleted id:#tera_slicer_obj do
			(
			tera_slicer.sel_obj = undefined
			tera_slicer.frac_obj.caption = "- NONE -"
			boundbox.enabled = false
			tera_slicer.frac_bot.enabled = false
			tera_slicer.lock_bot.enabled = false
			tera_slicer.lock_bot.checked = false
			tera_slicer.tera_Slicelock = false
			tera_slicer.iternum = tera_slicer.iter.value
			)		
		)
	)		

	fn CalculateVolume obj = 
		( 
		Volume= 0.0 
		theMesh = snapshotasmesh obj
		numFaces = theMesh.numfaces 
		for i = 1 to numFaces do 
			( 
			Face= getFace theMesh i 
			vert2 = getVert theMesh Face.z 
			vert1 = getVert theMesh Face.y 
			vert0 = getVert theMesh Face.x 
			dV = Dot (Cross (vert1 - vert0) (vert2 - vert0)) vert0
			Volume+= dV 
			) 
		delete theMesh
		Volume /= 22222
		Volume
		)
	
	fn setObjMass type =
		(
		the_sel = selection as array
		the_mult = reactormult_spn.value
		if the_sel != undefined do
			(
			for i in the_sel do
				(
				try
					(
					the_volume = CalculateVolume i
					the_mass = ( ( (the_volume as float)^(1.0/3.0)*0.0254) ^3 ) * 100 * the_mult
					case type of
						(
						1: 	(
							the_rigidobj = reactor.getRigidObject i
							the_rigidobj.mass = the_mass
							)
						2: 	(
							i.modifiers[#simcloth3].particleMass = the_mass
							)
						)
					)
				catch
					(
					format "% is an invalid node \n" i.name
					)
				)
			)
		)

	on rancolor_chk changed state do
		(tera_slicer.use_rancolor = state)
	on rancolor_bot pressed do
		(tera_slicer.RanColor() )
	on detach_all pressed do
	(
	detach_obj = selection
	if detach_obj[1] != undefined do
		(
		the_obj_count = detach_obj.count
		for i in 1 to the_obj_count do
			(
			max create mode
			tera_slicer.DetachPolyElements_fn detach_obj[i]			
			)
		)
	)
	on boundbox changed state do
	(
	sel_obj = tera_slicer.sel_obj
	case boundbox.checked of
		(
		true:
			(
			tera_slicer.bounds = true
			l = (sel_obj.max.y - sel_obj.min.y)
			w = (sel_obj.max.x - sel_obj.min.x)
			h = (sel_obj.max.z - sel_obj.min.z)
			c = sel_obj.center - [0, 0, (h/2)]
			bounder = Box name:(uniquename "Bounder_") lengthsegs:1 widthsegs:1 heightsegs:1 length:l width:w height:h pos:c wirecolor:(color 0 252 0)
			bounder.boxmode = true
			select bounder
			tera_slicer.bounder = bounder
			when bounder deleted id:#tera_slicer_bounder do
				(
				tera_slicer.bounds = false
				tera_slicer.bounder = undefined
				bounder = undefined
				boundbox.checked = false
				)
			)
		false:
			(
			if sel_obj != undefined do select sel_obj
			if bounder != undefined do 
				(
				tera_slicer.bounds = false
				tera_slicer.bounder = undefined				
				delete bounder
				bounder = undefined	
				)
			)
		)
	)
	on prog_chk changed state do
	(
	if state then
		(
		tera_slicer.width = 170
		tera_slicer.grp_status.width = 160
		tera_slicer.prog_enable = true
		)
	else 
		(
		tera_slicer.width = 155
		tera_slicer.grp_status.width = 145
		tera_slicer.prog_enable = false
		)
	)
	on xformoff_bot pressed do
	(
	the_sel = selection as array
	if the_sel != undefined do
		(
		max modify mode			
		for i in the_sel do
			(
			try
				(
				modPanel.setCurrentObject i.modifiers[#xform]				
				subobjectlevel = 0
				)
			catch
				(
				format "% has no Xform Modifier \n" i.name
				)
			)
		)		
	select the_sel
	)
	on reactormass_bot pressed do
		(setObjMass 1)
	on simclothmass_bot pressed do
		(setObjMass 2)
	on xform_chk changed state do
		(tera_slicer.xformval = state)
	on reactor_chk changed state do
		(tera_slicer.use_reactor = state)
	on simcloth_chk changed state do
		(tera_slicer.use_simcloth = state)
		
)
createdialog tera_slicer style:#(#style_titlebar, #style_border, #style_sysmenu,#style_minimizebox)
addsubrollout tera_slicer.tera_slicer_subroll tera_slicer_rotation_ops
addsubrollout tera_slicer.tera_slicer_subroll tera_slicer_boolean_mode
addsubrollout tera_slicer.tera_slicer_subroll tera_slicer_extraparameters
---



/* 
Version History:
2005-04-25 0.70 - Solid/Shell options are now working
				- info: percentage of open objects.	
2005-04-23 0.69 - Added Mass calculation for Reactor/simcloth3
				- Added Locked option (default)
				- xform mod not/applied during fragmentation
2005-04-16 0.68 - Fixed the code where subfragmenting is getting the [iter] instead is [subiter]
				- Fixed the Boolean mode not slicing properly when placed outside of 0,0,0
				- Added a subrollout, this way, I could easily add in additional parameters
				  in the future.
				- added capholes option for boolean mode
				- Added non-functional UI items also for boolean mode
					- power booleans
					- material id
					- solid/shell outputs
				- hide/unhide status info
				- randomize wire colors button
				- Rotation x,y,z
					- Lock & reset option
					- assign custom rotation controllers
				- Progress button icon
2005-04-15 0.67 - Added a filter function for picking polygon objects.
				  Now works on the japanses version of max.
				  Thanks to Mr. Masayuki Sato for prompting me on this. :)
				- Detection for deleted picked polygon object.
				- Fixed the bug that defaults the Slicer to Boolean Mode when opened.
				- Fixed: Can't see the version on the title bar.

Credits:
Terabyte Inc. / http://www.tera-byte.co.jp / Roy Constantino (my boss)
Hacksawtools:Chris Harvey for the Detach Elements Function
Masayuki Sato / http://www.maxuser.com
Neil Blevins for the bounding box script
Heikki Larson
Aimee Charmaine Claros
*/